package dao;

import logger.ExceptionLogger;
import logger.ExceptionLoggerImpl;
import hibernate.HibernateUtil;

import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 * Implementa las operacioens comunes a todos los DAO
 * @author DiegoAlejandro
 *
 */
public abstract class HibernateDAO implements DAO {
	private Session lastOpenSession;
	private static Logger logger = Logger.getLogger(HibernateDAO.class);
	
	public HibernateDAO(){
		super();
		this.lastOpenSession = null;
	}
	
	@Override
	public Session getSession() throws Exception{
		this.lastOpenSession = HibernateUtil.getSessionFactory().openSession();
		return this.lastOpenSession;
	}

	/**
	 * obtiene la última sesión abierta.
	 * @return lastOpenSession
	 */
	protected Session getLastOpenSession() {
		return lastOpenSession;
	}
	
	@Override
	public void close(Session session) throws Exception{
		session.close();
	}
	
	@Override
	public <T> Long save( T t ) throws Exception{
		Session session = this.getSession();
		Transaction trx = session.beginTransaction();
		
		try {
			Long id = (Long) session.save(t);
			trx.commit();
			return id;
		
		} catch (Exception e) {
			ExceptionLogger eLogger = new ExceptionLoggerImpl(logger);
			eLogger.logExceptionFatal(e);
			trx.rollback();
			
			throw e;
		
		} finally {
			this.close(session);
		}
	}
	
	@Override
	public <T> boolean delete(T t) throws Exception{
		Session session = this.getSession();
		Transaction trx = session.beginTransaction();
		
		try {
			session.delete(t);
			return true;
		
		} catch (Exception e) {
			ExceptionLogger eLogger = new ExceptionLoggerImpl(logger);
			eLogger.logExceptionFatal(e);
			trx.rollback();
			
			throw e;
		
		} finally {
			this.close(session);
		}		
	}
	
	@Override
	public <T> T update(T t) throws Exception{
		Session session = this.getSession();
		Transaction trx = session.beginTransaction();
		
		try {
			session.saveOrUpdate(t);
			trx.commit();
			return t;
		
		} catch (Exception e) {
			ExceptionLogger eLogger = new ExceptionLoggerImpl(logger);
			eLogger.logExceptionFatal(e);
			trx.rollback();
			
			throw e;
		
		} finally {
			this.close(session);
		}
	}
	
	public <T> T getById(Long id, Class<T> clazz) throws Exception{
		Session session = this.getSession();
		T t = (T) session.get(clazz, id);
		return t;
	}
}
